package com.ecommerce.product.service.impl;

import com.ecommerce.product.dto.*;
import com.ecommerce.product.entity.Product;
import com.ecommerce.product.entity.ProductStockLog;
import com.ecommerce.product.config.KafkaConfig;
import com.ecommerce.common.event.StockLogEvent;
import com.ecommerce.product.repository.CategoryRepository;
import com.ecommerce.product.repository.ProductRepository;
import com.ecommerce.product.repository.ProductStockLogRepository;
import com.ecommerce.product.service.ProductService;
import com.ecommerce.product.service.RedisHealthService;
import com.ecommerce.product.dto.ProductMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import jakarta.persistence.EntityManager;
import jakarta.persistence.criteria.Predicate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 产品服务实现类
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class ProductServiceImpl implements ProductService {

    private final ProductRepository productRepository;
    private final ProductStockLogRepository stockLogRepository;
    private final CategoryRepository categoryRepository;
    private final ProductMapper productMapper;
    private final EntityManager entityManager;
    private final RedisHealthService redisHealthService;
    private final KafkaConfig.StockLogEventProducer stockLogEventProducer;

    @Override
    @Transactional
    public ProductResponse createProduct(ProductCreateRequest createRequest) {
        log.info("创建产品, 请求参数: {}", createRequest);
        
        // 检查分类是否存在
        if (!categoryRepository.existsById(createRequest.getCategoryId())) {
            throw new RuntimeException("分类不存在: " + createRequest.getCategoryId());
        }
        
        Product product = productMapper.createRequestToEntity(createRequest);
        product = productRepository.save(product);
        
        log.info("产品创建成功, ID: {}", product.getId());
        return productMapper.entityToResponseDto(product);
    }

    @Override
    @Transactional
    @CacheEvict(value = "products", key = "#productId")
    public ProductResponse updateProduct(Long productId, ProductUpdateRequest updateRequest) {
        log.info("更新产品, ID: {}, 请求参数: {}", productId, updateRequest);
        
        Product product = productRepository.findById(productId)
                .orElseThrow(() -> new RuntimeException("产品不存在: " + productId));
        
        productMapper.updateEntity(product, updateRequest);
        product = productRepository.save(product);
        
        log.info("产品更新成功, ID: {}", productId);
        return productMapper.entityToResponseDto(product);
    }

    @Override
    @Cacheable(value = "products", key = "#productId")
    public ProductResponse getProductById(Long productId) {
        log.debug("获取产品详情, ID: {}", productId);  // 改为debug级别，减少日志输出
        
        Product product = productRepository.findById(productId)
                .orElseThrow(() -> new RuntimeException("产品不存在: " + productId));
        
        return productMapper.entityToResponseDto(product);
    }

    @Override
    public ProductPageResponse getProducts(Integer page, Integer size) {
        log.debug("分页获取产品列表, 页码: {}, 每页大小: {}", page, size);  // 改为debug级别
        
        Pageable pageable = PageRequest.of(page - 1, size);
        Page<Product> productPage = productRepository.findAll(pageable);
        
        List<ProductResponse> products = productPage.getContent().stream()
                .map(productMapper::entityToResponseDto)
                .collect(Collectors.toList());
        
        ProductPageResponse response = new ProductPageResponse();
        response.setProducts(products);
        response.setTotal(productPage.getTotalElements());
        response.setPage(page);
        response.setSize(size);
        response.setTotalPages(productPage.getTotalPages());
        
        return response;
    }

    @Override
    public ProductPageResponse getProductsWithFilters(Integer page, Integer size, Long categoryId, String keyword, String stockFilter) {
        log.debug("分页获取产品列表（带筛选）, 页码: {}, 每页大小: {}, 分类ID: {}, 关键词: {}, 库存筛选: {}", 
                page, size, categoryId, keyword, stockFilter);  // 改为debug级别
        
        Pageable pageable = PageRequest.of(page - 1, size);
        Page<Product> productPage;
        
        // 构建Specification进行动态查询
        Specification<Product> spec = (root, query, criteriaBuilder) -> {
            List<Predicate> predicates = new ArrayList<>();
            
            // 分类筛选
            if (categoryId != null) {
                predicates.add(criteriaBuilder.equal(root.get("categoryId"), categoryId));
            }
            
            // 关键词搜索
            if (keyword != null && !keyword.trim().isEmpty()) {
                String likeKeyword = "%" + keyword.trim() + "%";
                predicates.add(criteriaBuilder.or(
                    criteriaBuilder.like(criteriaBuilder.lower(root.get("name")), likeKeyword.toLowerCase()),
                    criteriaBuilder.like(criteriaBuilder.lower(root.get("description")), likeKeyword.toLowerCase())
                ));
            }
            
            // 库存筛选
            if (stockFilter != null && !stockFilter.trim().isEmpty()) {
                switch (stockFilter) {
                    case "in_stock":
                        predicates.add(criteriaBuilder.greaterThan(root.get("stock"), 0));
                        break;
                    case "low_stock":
                        predicates.add(criteriaBuilder.and(
                            criteriaBuilder.greaterThan(root.get("stock"), 0),
                            criteriaBuilder.lessThan(root.get("stock"), 10)
                        ));
                        break;
                    case "out_of_stock":
                        predicates.add(criteriaBuilder.equal(root.get("stock"), 0));
                        break;
                }
            }
            
            return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
        };
        
        productPage = productRepository.findAll(spec, pageable);
        
        List<ProductResponse> products = productPage.getContent().stream()
                .map(productMapper::entityToResponseDto)
                .collect(Collectors.toList());
        
        ProductPageResponse response = new ProductPageResponse();
        response.setProducts(products);
        response.setTotal(productPage.getTotalElements());
        response.setPage(page);
        response.setSize(size);
        response.setTotalPages(productPage.getTotalPages());
        
        return response;
    }

    @Override
    @Transactional
    @CacheEvict(value = "products", key = "#productId")
    public void deleteProduct(Long productId) {
        log.info("删除产品, ID: {}", productId);
        
        if (!productRepository.existsById(productId)) {
            throw new RuntimeException("产品不存在: " + productId);
        }
        
        productRepository.deleteById(productId);
        log.info("产品删除成功, ID: {}", productId);
    }

    @Override
    @Transactional
    public void reduceStock(Long productId, Integer quantity) {
        log.info("减少产品库存, 产品ID: {}, 数量: {}", productId, quantity);
        
        if (quantity <= 0) {
            throw new RuntimeException("减少库存数量必须大于0");
        }
        
        // 使用悲观锁获取产品，防止并发问题
        Product product = productRepository.findByIdWithLock(productId)
                .orElseThrow(() -> new RuntimeException("产品不存在"));
        
        // 记录变动前库存
        int stockBefore = product.getStock();
        
        // 检查库存是否充足
        if (stockBefore < quantity) {
            throw new RuntimeException("库存不足，当前库存: " + stockBefore + ", 需要数量: " + quantity);
        }
        
        // 扣减库存
        product.setStock(stockBefore - quantity);
        product = productRepository.save(product);
        
        // 异步记录库存日志，减少主流程延迟
        asyncSaveStockLog(productId, null, "REDUCE", quantity, stockBefore, product.getStock(), "订单库存扣减");
        
        log.info("产品库存减少成功, 产品ID: {}, 原库存: {}, 新库存: {}", 
                productId, stockBefore, product.getStock());
    }

    @Override
    @Transactional
    public void increaseStock(Long productId, Integer quantity) {
        log.info("增加产品库存, 产品ID: {}, 数量: {}", productId, quantity);
        
        if (quantity <= 0) {
            throw new RuntimeException("增加库存数量必须大于0");
        }
        
        // 使用悲观锁获取产品，防止并发问题
        Product product = productRepository.findByIdWithLock(productId)
                .orElseThrow(() -> new RuntimeException("产品不存在: " + productId));
        
        // 记录变动前库存
        int stockBefore = product.getStock();
        
        // 增加库存
        product.setStock(stockBefore + quantity);
        product = productRepository.save(product);
        
        // 异步记录库存日志，减少主流程延迟
        asyncSaveStockLog(productId, null, "INCREASE", quantity, stockBefore, product.getStock(), "订单取消库存回滚");
        
        log.info("产品库存增加成功, 产品ID: {}, 原库存: {}, 新库存: {}", 
                productId, stockBefore, product.getStock());
    }

    /**
     * 异步保存库存日志
     */
    @Async
    public void asyncSaveStockLog(Long productId, Long orderId, String changeType, 
                                 Integer quantity, int stockBefore, int stockAfter, String remark) {
        try {
            ProductStockLog stockLog = new ProductStockLog();
            stockLog.setProductId(productId);
            stockLog.setOrderId(orderId);
            stockLog.setChangeType(changeType);
            stockLog.setQuantity(quantity);
            stockLog.setStockBefore(stockBefore);
            stockLog.setStockAfter(stockAfter);
            stockLog.setRemark(remark);
            stockLogRepository.save(stockLog);
            
            // 发送库存日志事件到Kafka
            try {
                StockLogEvent event = StockLogEvent.builder()
                        .productId(productId)
                        .orderId(orderId)
                        .changeType(changeType)
                        .quantity(quantity)
                        .stockBefore(stockBefore)
                        .stockAfter(stockAfter)
                        .remark(remark)
                        .timestamp(LocalDateTime.now())
                        .build();
                
                stockLogEventProducer.sendMessage(event);
                log.debug("库存日志事件已发送到Kafka - 产品ID: {}, 订单ID: {}", productId, orderId);
                
            } catch (Exception e) {
                log.error("发送库存日志事件失败 - 产品ID: {}, 订单ID: {}, 错误: {}", productId, orderId, e.getMessage(), e);
                // 事件发送失败不影响库存日志保存流程
            }
            
        } catch (Exception e) {
            log.error("异步保存库存日志失败, 产品ID: {}", productId, e);
        }
    }

    @Override
    @Cacheable(value = "hotProducts", key = "'limit:' + #limit", unless = "#result == null or #result.isEmpty()")
    public List<ProductResponse> getHotProducts(Integer limit) {
        log.info("获取热门商品, 限制数量: {}", limit);
        
        // 检查Redis连接状态
        if (!redisHealthService.isRedisAvailable()) {
            log.warn("Redis连接不可用，直接查询数据库获取热门商品");
            return getHotProductsFromDatabase(limit);
        }
        
        try {
            return getHotProductsFromDatabase(limit);
        } catch (Exception e) {
            log.error("获取热门商品失败，尝试重新连接Redis", e);
            
            // 重新检查Redis连接
            redisHealthService.isRedisAvailable();
            
            // 再次尝试获取数据
            try {
                return getHotProductsFromDatabase(limit);
            } catch (Exception ex) {
                log.error("重试后仍然失败，返回空列表", ex);
                return new ArrayList<>();
            }
        }
    }
    
    /**
     * 从数据库获取热门商品
     */
    private List<ProductResponse> getHotProductsFromDatabase(Integer limit) {
        log.debug("从数据库获取热门商品, 限制数量: {}", limit);
        
        Pageable pageable = PageRequest.of(0, limit);
        List<Product> hotProducts = productRepository.findTopNByOrderBySalesDesc(pageable);
        
        List<ProductResponse> result = hotProducts.stream()
                .map(productMapper::entityToResponseDto)
                .collect(Collectors.toList());
        
        log.debug("成功获取热门商品，数量: {}", result.size());
        return result;
    }

    @Override
    public ProductPageResponse searchProducts(String keyword, Integer page, Integer size) {
        log.debug("搜索产品, 关键词: {}, 页码: {}, 每页大小: {}", keyword, page, size);  // 改为debug级别
        
        Pageable pageable = PageRequest.of(page - 1, size);
        Page<Product> productPage;
        
        if (keyword == null || keyword.trim().isEmpty()) {
            // 如果关键词为空，则返回所有产品
            productPage = productRepository.findAll(pageable);
        } else {
            // 根据关键词搜索产品
            productPage = productRepository.findByNameOrDescriptionContainingIgnoreCase(keyword, pageable);
        }
        
        List<ProductResponse> products = productPage.getContent().stream()
                .map(productMapper::entityToResponseDto)
                .collect(Collectors.toList());
        
        ProductPageResponse response = new ProductPageResponse();
        response.setProducts(products);
        response.setTotal(productPage.getTotalElements());
        response.setPage(page);
        response.setSize(size);
        response.setTotalPages(productPage.getTotalPages());
        
        return response;
    }

    @Override
    public ProductPageResponse getProductsByCategory(Long categoryId, Integer page, Integer size) {
        log.debug("按分类获取产品, 分类ID: {}, 页码: {}, 每页大小: {}", categoryId, page, size);  // 改为debug级别
        
        Pageable pageable = PageRequest.of(page - 1, size);
        Page<Product> productPage = productRepository.findByCategoryId(categoryId, pageable);
        
        List<ProductResponse> products = productPage.getContent().stream()
                .map(productMapper::entityToResponseDto)
                .collect(Collectors.toList());
        
        ProductPageResponse response = new ProductPageResponse();
        response.setProducts(products);
        response.setTotal(productPage.getTotalElements());
        response.setPage(page);
        response.setSize(size);
        response.setTotalPages(productPage.getTotalPages());
        
        return response;
    }

    @Override
    public ProductStatsResponse getProductStats() {
        log.debug("获取商品统计信息");  // 改为debug级别
        
        try {
            // 获取总商品数量
            long totalProducts = 0;
            try {
                totalProducts = productRepository.count();
                log.debug("总商品数量: {}", totalProducts);  // 改为debug级别
            } catch (Exception e) {
                log.error("获取总商品数量失败", e);
            }
            
            // 获取总分类数量（只统计未删除的可见分类）
            long totalCategories = 0;
            try {
                totalCategories = categoryRepository.countByDeleteStatus(0); // 0表示未删除
                log.debug("总分类数量: {}", totalCategories);  // 改为debug级别
            } catch (Exception e) {
                log.error("获取总分类数量失败", e);
            }
            
            ProductStatsResponse response = new ProductStatsResponse();
            response.setTotalProducts(totalProducts);
            response.setTotalCategories(totalCategories);
            
            return response;
        } catch (Exception e) {
            log.error("获取商品统计信息失败", e);
            throw new RuntimeException("获取商品统计信息失败", e);
        }
    }
}